﻿using ApiTemplateGenerate.ModelInfo;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Linq;
using HXH.Tools.ExtensionAttribute;

namespace ApiTemplateGenerate.Extend
{
    /// <summary>
    /// 类型扩展方法
    /// </summary>
    public static class TypeExtend
    {
        #region 基础
        /// <summary>
        /// 判断是否是可空类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsNullableType(this Type type)
        {
            if (type.IsGenericType)
            {
                var definition = type.GetGenericTypeDefinition();
                if (definition != null && definition == typeof(Nullable<>))
                {

                    return true;
                }
                else
                    return false;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 判断是否是可空类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsNullableType(this PropertyInfo propertyInfo)
        {
            return propertyInfo.PropertyType.IsNullableType();
        }
        /// <summary>
        /// 判断是否是 IEnumerable<> IList<> List<> 类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsIEnumerableType(this Type type)
        {
            if (type.IsGenericType)
            {
                var definition = type.GetGenericTypeDefinition();
                if (definition != null && (definition == typeof(IEnumerable<>) || definition == typeof(IList<>) || definition == typeof(List<>)))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }

        }
        /// <summary>
        /// 判断是否是 IEnumerable<> IList<> List<> 类型
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <returns></returns>
        public static bool IsIEnumerableType(this PropertyInfo propertyInfo)
        {
            return propertyInfo.PropertyType.IsIEnumerableType();
        }
        #endregion


        #region 获取描述
        public static string GetDescribe(this Type type)
        {
            object[] objAttrs = type.GetCustomAttributes(typeof(DescribeAttribute), true);
            if (objAttrs.Length > 0)
            {
                DescribeAttribute attr = objAttrs[0] as DescribeAttribute;
                if (attr != null)
                {
                    return $"{attr.Describe}";
                }
            }
            return string.Empty;
        }
        public static string GetDescribe(this MethodInfo type)
        {
            object[] objAttrs = type.GetCustomAttributes(typeof(DescribeAttribute), true);
            if (objAttrs.Length > 0)
            {
                DescribeAttribute attr = objAttrs[0] as DescribeAttribute;
                if (attr != null)
                {
                    return $"{attr.Describe}";
                }
            }
            return string.Empty;
        }
        public static bool GetTSFileDownload(this MethodInfo type)
        {
            object[] objAttrs = type.GetCustomAttributes(typeof(TSFileDownloadAttribute), true);
            if (objAttrs.Length > 0)
            {
                return true;
            }
            return false;
        }
        public static bool GetTSFileImport(this MethodInfo type)
        {
            object[] objAttrs = type.GetCustomAttributes(typeof(TSFileImportAttribute), true);
            if (objAttrs.Length > 0)
            {
                return true;
            }
            return false;
        }
        public static string GetDescribe(this System.Reflection.ParameterInfo type)
        {
            object[] objAttrs = type.GetCustomAttributes(typeof(DescribeAttribute), true);
            if (objAttrs.Length > 0)
            {
                DescribeAttribute attr = objAttrs[0] as DescribeAttribute;
                if (attr != null)
                {
                    return $"{attr.Describe}";
                }
            }
            return string.Empty;
        }
        public static string GetDescribe(this PropertyInfo type)
        {
            object[] objAttrs = type.GetCustomAttributes(typeof(DescribeAttribute), true);
            if (objAttrs.Length > 0)
            {
                DescribeAttribute attr = objAttrs[0] as DescribeAttribute;
                if (attr != null)
                {
                    return $"{attr.Describe}";
                }
            }
            return string.Empty;
        }
        public static string GetDescribe(this FieldInfo type)
        {
            object[] objAttrs = type.GetCustomAttributes(typeof(DescribeAttribute), true);
            if (objAttrs.Length > 0)
            {
                DescribeAttribute attr = objAttrs[0] as DescribeAttribute;
                if (attr != null)
                {
                    return $"{attr.Describe}";
                }
            }
            return string.Empty;
        }
        #endregion



        #region 扩展
        public static HashSet<string> ClassNames = new HashSet<string>();
        /// <summary>
        /// 获取类型信息
        /// </summary>
        /// <param name="typeInfo"></param>
        /// <returns></returns>
        public static ApiTemplateGenerate.ModelInfo.TypeInfo GetTypeInfo(this Type typeInfo)
        {
            if (typeInfo.IsPrimitive || typeInfo.Name == "String" || typeInfo.Name == "Object" || typeInfo.Name == "DateTime" || typeInfo.Name == "Decimal")//是否是基元类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo
                { Type = typeInfo, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.BaseType, Name = typeInfo.Name };
            }
            if (typeInfo.IsClass && !typeInfo.IsPrimitive && !typeInfo.IsGenericType)//class类型
            {
                if (ClassNames.Contains(typeInfo.Name))
                {
                    return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.GetType(), TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Other, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                }
                else
                {
                    ClassNames.Add(typeInfo.Name);
                    var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Class, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                    foreach (var property in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                    {
                        var resultChild = GetTypeInfo(property);
                        result.TypeInfoChild.Add(resultChild);
                    }
                    return result;
                }
            }
            if (typeInfo.IsArray)//数组类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IsArray, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
            }
            if (typeInfo.IsEnum)//枚举类型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Enum, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };

                foreach (var field in typeInfo.GetFields())
                {
                    if (field.FieldType.IsEnum == true)
                    {
                        //TODO 待处理枚举值类型是类之类的类型 目前只能处理基本类型
                        result.TypeInfoChild.Add(new ModelInfo.TypeInfo
                        {
                            Describe = field.GetDescribe(),
                            Name = field.Name,
                            Type = field.FieldType,
                            TypeEnum= ApiTemplateGenerate.ModelInfo.TypeEnum.BaseType,
                            Value = field.GetRawConstantValue()
                        });
                    }
                }

                return result;
            }
            if (typeInfo.IsIEnumerableType())//判断是否是 IEnumerable<> IList<> List<> 类型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IEnumerable, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                var resultChild = GetTypeInfo(typeInfo.GetGenericArguments()[0]);
                result.TypeInfoChild.Add(resultChild);
                return result;
            }
            if (typeInfo.IsGenericType && !typeInfo.IsNullableType())//是否是泛型并且不是可空类型泛型
            {
                var isSuccess = true;
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Generic, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                foreach (var property in typeInfo.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    var resultProperty = GetTypeInfo(property);
                    if (isSuccess)
                    {
                        if (property.PropertyType == typeInfo.GetGenericArguments()[0])
                        {
                            resultProperty.IsT = true;
                            isSuccess = false;
                        }
                        if (!(resultProperty.TypeEnum == ModelInfo.TypeEnum.BaseType))
                        {
                            if (IsT(typeInfo, resultProperty))
                            {
                                resultProperty.IsT = true;
                                isSuccess = false;
                            }
                        }
                    }
                    result.TypeInfoChild.Add(resultProperty);
                }
                return result;
            }
            if (typeInfo.IsNullableType())//可空类型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IsNullType, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                var resultChild = GetTypeInfo(typeInfo.GetGenericArguments()[0]);
                result.TypeInfoChild.Add(resultChild);
                return result;
            }
            else//其它类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.GetType(), TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Other, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
            }
        }

        private static bool IsT(Type typeInfo, ModelInfo.TypeInfo resultProperty)
        {
            foreach (var item in resultProperty.TypeInfoChild)
            {
                if (item.Type == typeInfo.GetGenericArguments()[0])
                {
                    return true;
                }
                else
                {
                    return IsT(typeInfo, item);
                }
            }
            return false;
        }
        private static bool IsT(PropertyInfo typeInfo, ModelInfo.TypeInfo resultProperty)
        {
            foreach (var item in resultProperty.TypeInfoChild)
            {
                if (item.Type == typeInfo.PropertyType.GetGenericArguments()[0])
                {
                    return true;
                }
                else
                {
                    return IsT(typeInfo, item);
                }
            }
            return false;
        }
        private static bool IsT(System.Reflection.ParameterInfo typeInfo, ModelInfo.TypeInfo resultProperty)
        {
            foreach (var item in resultProperty.TypeInfoChild)
            {
                if (item.Type == typeInfo.ParameterType.GetGenericArguments()[0])
                {
                    return true;
                }
                else
                {
                    return IsT(typeInfo, item);
                }
            }
            return false;
        }

        /// <summary>
        /// 获取类型信息
        /// </summary>
        /// <param name="typeInfo"></param>
        /// <returns></returns>
        public static ApiTemplateGenerate.ModelInfo.TypeInfo GetTypeInfo(this PropertyInfo typeInfo)
        {
            if (typeInfo.PropertyType.IsPrimitive || typeInfo.PropertyType.Name == "String" || typeInfo.PropertyType.Name == "Object" || typeInfo.PropertyType.Name == "DateTime" || typeInfo.PropertyType.Name == "Decimal")//是否是基元类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.PropertyType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.BaseType, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
            }
            if (typeInfo.PropertyType.IsClass && !typeInfo.PropertyType.IsPrimitive && !typeInfo.PropertyType.IsGenericType && !typeInfo.PropertyType.IsArray)//class类型
            {
                if (ClassNames.Contains(typeInfo.Name))
                {
                    return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.GetType(), TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Other, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                }
                else
                {
                    ClassNames.Add(typeInfo.Name);
                    var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.PropertyType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Class, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                    foreach (var property in typeInfo.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                    {
                        var resultChild = GetTypeInfo(property);
                        result.TypeInfoChild.Add(resultChild);
                    }
                    return result;
                }
            }
            if (typeInfo.PropertyType.IsArray)//数组类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.PropertyType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IsArray, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
            }
            if (typeInfo.PropertyType.IsEnum)//枚举类型
            {
                var result= new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.PropertyType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Enum, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                foreach (var field in typeInfo.PropertyType.GetFields())
                {
                    if (field.FieldType.IsEnum == true)
                    {
                        //TODO 待处理枚举值类型是类之类的类型 目前只能处理基本类型
                        result.TypeInfoChild.Add(new ModelInfo.TypeInfo
                        {
                            Describe = field.GetDescribe(),
                            Name = field.Name,
                            Type = field.FieldType,
                            TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.BaseType,
                            Value = field.GetRawConstantValue()
                        });
                    }
                }

                return result;
            }
            if (typeInfo.IsIEnumerableType())//判断是否是 IEnumerable<> IList<> List<> 类型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.PropertyType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IEnumerable, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                var resultChild = GetTypeInfo(typeInfo.PropertyType.GetGenericArguments()[0]);
                result.TypeInfoChild.Add(resultChild);
                return result;
            }
            if (typeInfo.PropertyType.IsGenericType && !typeInfo.IsNullableType())//是否是泛型并且不是可空类型泛型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.PropertyType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Generic, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                foreach (var property in typeInfo.PropertyType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    var resultProperty = GetTypeInfo(property);
                    if (property.PropertyType == typeInfo.PropertyType.GetGenericArguments()[0])
                    {
                        resultProperty.IsT = true;
                    }
                    //if (IsT(typeInfo, resultProperty))
                    //{
                    //    resultProperty.IsT = true;
                    //}
                    result.TypeInfoChild.Add(resultProperty);
                }
                return result;
            }
            if (typeInfo.IsNullableType())//可空类型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.PropertyType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IsNullType, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                var resultChild = GetTypeInfo(typeInfo.PropertyType.GetGenericArguments()[0]);
                result.TypeInfoChild.Add(resultChild);
                return result;
            }
            else//其它类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.GetType(), TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Other, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
            }
        }
        /// <summary>
        /// 获取类型信息
        /// </summary>
        /// <param name="typeInfo"></param>
        /// <returns></returns>
        public static ApiTemplateGenerate.ModelInfo.TypeInfo GetTypeInfo(this System.Reflection.ParameterInfo typeInfo)
        {
            if (typeInfo.ParameterType.IsPrimitive || typeInfo.ParameterType.Name == "String" || typeInfo.ParameterType.Name == "Object" || typeInfo.ParameterType.Name == "DateTime" || typeInfo.ParameterType.Name == "Decimal")//是否是基元类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.ParameterType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.BaseType, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
            }
            if (typeInfo.ParameterType.IsClass && !typeInfo.ParameterType.IsPrimitive && !typeInfo.ParameterType.IsGenericType && !typeInfo.ParameterType.IsArray)//class类型
            {
                if (ClassNames.Contains(typeInfo.Name))
                {
                    return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.GetType(), TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Other, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                }
                else
                {
                    ClassNames.Add(typeInfo.Name);
                    var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.ParameterType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Class, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                    foreach (var property in typeInfo.ParameterType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                    {
                        var resultChild = GetTypeInfo(property);
                        result.TypeInfoChild.Add(resultChild);
                    }
                    return result;
                }
            }
            if (typeInfo.ParameterType.IsArray)//数组类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.ParameterType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IsArray, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
            }
            if (typeInfo.ParameterType.IsEnum)//枚举类型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.ParameterType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Enum, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                foreach (var field in typeInfo.ParameterType.GetFields())
                {
                    if (field.FieldType.IsEnum == true)
                    {
                        //TODO 待处理枚举值类型是类之类的类型 目前只能处理基本类型
                        result.TypeInfoChild.Add(new ModelInfo.TypeInfo
                        {
                            Describe = field.GetDescribe(),
                            Name = field.Name,
                            Type = field.FieldType,
                            TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.BaseType,
                            Value = field.GetRawConstantValue()
                        });
                    }
                }

                return result;
            }
            if (typeInfo.ParameterType.IsIEnumerableType())//判断是否是 IEnumerable<> IList<> List<> 类型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.ParameterType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IEnumerable, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                var resultChild = GetTypeInfo(typeInfo.ParameterType.GetGenericArguments()[0]);
                result.TypeInfoChild.Add(resultChild);
                return result;
            }
            if (typeInfo.ParameterType.IsGenericType && !typeInfo.ParameterType.IsNullableType())//是否是泛型并且不是可空类型泛型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.ParameterType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Generic, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                foreach (var property in typeInfo.ParameterType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
                {
                    var resultProperty = GetTypeInfo(property);
                    if (property.PropertyType == typeInfo.ParameterType.GetGenericArguments()[0])
                    {
                        resultProperty.IsT = true;
                    }
                    //if (IsT(typeInfo, resultProperty))
                    //{
                    //    resultProperty.IsT = true;
                    //}
                    result.TypeInfoChild.Add(resultProperty);
                }
                return result;
            }
            if (typeInfo.ParameterType.IsNullableType())//可空类型
            {
                var result = new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.ParameterType, TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.IsNullType, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
                var resultChild = GetTypeInfo(typeInfo.ParameterType.GetGenericArguments()[0]);
                result.TypeInfoChild.Add(resultChild);
                return result;
            }
            else//其它类型
            {
                return new ApiTemplateGenerate.ModelInfo.TypeInfo { Type = typeInfo.GetType(), TypeEnum = ApiTemplateGenerate.ModelInfo.TypeEnum.Other, Name = typeInfo.Name, Describe = typeInfo.GetDescribe() };
            }
        }
        #endregion
    }
}
